#include "pch.hpp"
#include "System.hpp"

#include "XmlReader.hpp"
#include "XmlWriter.hpp"
#include "InfoReader.hpp"
#include "InfoWriter.hpp"




DatabaseSystem::DatabaseSystem(const EngineInfo& info)
	: m_logger(info.serviceProvider->service<Logger>())
{
	// Register all basic readers
	// For now, there is only the XmlReader/Writer
	registerExtension("xml", &DatabaseXmlReader::create, &DatabaseXmlWriter::create);
	registerExtension("info", &DatabaseInfoReader::create, &DatabaseInfoWriter::create);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

DatabaseSystem::~DatabaseSystem()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




QString DatabaseSystem::name() const
{
	return __STR__(DatabaseSystem);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void DatabaseSystem::update()
{}
///////////////////////////////////////////////////////////////////////////////////////////////////




void DatabaseSystem::load(const QString& fname)
{
	QFileInfo inf(fname);
	QString ext = inf.completeSuffix().toLower();

	// Create an instance of the reader, dedicated to those type of files.
	STRICT_PTR(DatabaseReader) reader = m_readerFactory.create(ext, fname, m_itemFactory, m_logger, ptr());



	// Now read all items from the file and insert them into the list of items
	LOOSE_PTR(DatabaseItem) item;
	while(item = reader->read())
	{
		// Our database stores strict pointers, and the reader
		// returns loose pointers, but those can be implicitly
		// converted to strict ones (strict works like a qualifier)
		m_items.insert(std::make_pair(item->name(), item));
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void DatabaseSystem::save(const QString& fname)
{
	QFileInfo inf(fname);
	QString ext = inf.completeSuffix().toLower();

	// Create an instance of the writer, dedicated to those type of files.
	DatabaseWriterPtr writer = m_writerFactory.create(ext, fname, m_logger);

	// Simply serialize all items
	foreach(const ItemPair& item, m_items)
	{
		// Serialization doesn't tolerate any exceptions (there shouldn't be any)
		// so we don't catch anything.
		writer->write(item.second);
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void DatabaseSystem::registerExtension(const QString& extension, const ReaderFunctor& reader, const WriterFunctor& writer)
{
	m_readerFactory.registerFunctor(extension, reader);
	m_writerFactory.registerFunctor(extension, writer);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void DatabaseSystem::registerItemType(const QString& type, const ItemFunctor& functor)
{
	m_itemFactory.registerFunctor(type, functor);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void DatabaseSystem::addItem(const STRICT_PTR(DatabaseItem)& item)
{
	ItemMap::const_iterator i = m_items.find(item->name());
	if(i != m_items.end())
		BOOSTEXT_THROW(exception(format("There already is an item named '%1%'") % item->name()));

	if(!m_itemFactory.contains(item->type()))
		BOOSTEXT_THROW(exception(format("The Item-Type '%1%' is not known to the DatabaseSystem") % item->type()));

	m_items.insert(std::make_pair(item->name(), item));
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void DatabaseSystem::removeItem(const QString& name)
{
	ItemMap::iterator i = m_items.find(name);
	if(i != m_items.end())
		BOOSTEXT_THROW(exception(format("There is no item named '%1%'") % name));

	m_items.erase(i);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool DatabaseSystem::containsItem(const QString& name) const
{
	return m_items.find(name) != m_items.end();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

STRICT_PTR(DatabaseItem) DatabaseSystem::item(const QString& name) const
{
	ItemMap::const_iterator i = m_items.find(name);
	if(i == m_items.end())
		BOOSTEXT_THROW(exception(format("The Item named '%1%' could not be found") % name));

	return i->second;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

const DatabaseSystem::ItemMap& DatabaseSystem::items() const
{
	return m_items;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

DatabaseSystem::ItemMap DatabaseSystem::items(const QString& type) const
{
	ItemMap items;

	foreach(const ItemPair& item, m_items)
	{
		if(item.second->type() == type)
			items.insert(std::make_pair(item.second->name(), item.second));
	}

	return items;
}
///////////////////////////////////////////////////////////////////////////////////////////////////
